{
  "cells": [
    {
      "metadata": {
        "id": "zWgEkOAO9OVz"
      },
      "cell_type": "markdown",
      "source": [
        "# An example implementing the three key questions\n",
        "\n",
        "March and Olsen (2011) posit that humans generally act as though they choose their actions by answering three key questions:\n",
        "\n",
        "1. What kind of situation is this?\n",
        "2. What kind of person am I?\n",
        "3. What does a person such as I do in a situation such as this?\n",
        "\n",
        "The agents used in this example implement these components. The premise of the simulation is that 4 friends are stuck at a snowed in pub. Also, it has just come to light that Alice stole Bob's car and crashed it.\n"
      ]
    },
    {
      "metadata": {
        "id": "bFZYhMyM4A3z"
      },
      "cell_type": "markdown",
      "source": [
        "\u003ca href=\"https://colab.research.google.com/github/google-deepmind/concordia/blob/main/examples/deprecated/three_key_questions.ipynb\" target=\"_parent\"\u003e\u003cimg src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/\u003e\u003c/a\u003e"
      ]
    },
    {
      "metadata": {
        "id": "J2TwJrZ08wXz"
      },
      "cell_type": "markdown",
      "source": [
        "## Setup and imports"
      ]
    },
    {
      "metadata": {
        "id": "tkCJgbFFvaAB"
      },
      "cell_type": "code",
      "source": [
        "# @title Colab-specific setup (use a CodeSpace to avoid the need for this).\n",
        "try:\n",
        "  %env COLAB_RELEASE_TAG\n",
        "except:\n",
        "  pass  # Not running in colab.\n",
        "else:\n",
        "  %pip install --ignore-requires-python --requirement 'https://raw.githubusercontent.com/google-deepmind/concordia/main/examples/requirements.in' 'git+https://github.com/google-deepmind/concordia.git#egg=gdm-concordia'\n",
        "  %pip list"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "-qLG5ExLqpWa"
      },
      "cell_type": "code",
      "source": [
        "# @title Imports\n",
        "\n",
        "import collections\n",
        "import concurrent.futures\n",
        "import datetime\n",
        "\n",
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "import sentence_transformers\n",
        "\n",
        "from IPython import display\n",
        "\n",
        "from concordia.agents.deprecated import deprecated_agent as basic_agent\n",
        "from concordia.components import deprecated as generic_components\n",
        "from concordia.associative_memory.deprecated import associative_memory\n",
        "from concordia.associative_memory.deprecated import blank_memories\n",
        "from concordia.associative_memory.deprecated import formative_memories\n",
        "from concordia.associative_memory.deprecated import importance_function\n",
        "from concordia.clocks import game_clock\n",
        "from concordia.components.agent.deprecated import to_be_deprecated as components\n",
        "from concordia.components.game_master import deprecated as gm_components\n",
        "from concordia.environment.deprecated import game_master\n",
        "from concordia.contrib.language_models.openai import gpt_model\n",
        "from concordia.deprecated.metrics import goal_achievement\n",
        "from concordia.deprecated.metrics import common_sense_morality\n",
        "from concordia.deprecated.metrics import opinion_of_others\n",
        "from concordia.utils import html as html_lib\n",
        "from concordia.utils.deprecated import measurements as measurements_lib\n",
        "from concordia.utils import plotting\n"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "I3OtW8flCJSC"
      },
      "cell_type": "code",
      "source": [
        "# Setup sentence encoder\n",
        "st_model = sentence_transformers.SentenceTransformer(\n",
        "    'sentence-transformers/all-mpnet-base-v2')\n",
        "embedder = lambda x: st_model.encode(x, show_progress_bar=False)\n"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "cugwvFIKv5AS"
      },
      "cell_type": "code",
      "source": [
        "# @title Language Model - pick your model and provide keys\n",
        "\n",
        "# By default this colab uses GPT-4, so you must provide an API key.\n",
        "# Note that it is also possible to use local models or other API models,\n",
        "# simply replace this cell with the correct initialization for the model\n",
        "# you want to use.\n",
        "GPT_API_KEY = '' #@param {type: 'string'}\n",
        "GPT_MODEL_NAME = 'gpt-4o' #@param {type: 'string'}\n",
        "\n",
        "if not GPT_API_KEY:\n",
        "  raise ValueError('GPT_API_KEY is required.')\n",
        "\n",
        "model = gpt_model.GptLanguageModel(api_key=GPT_API_KEY,\n",
        "                                   model_name=GPT_MODEL_NAME)\n"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "z9HYjZgyakc_"
      },
      "cell_type": "markdown",
      "source": [
        "## Configuring the generic knowledge of players and GM."
      ]
    },
    {
      "metadata": {
        "id": "TeVYseoD2WYa"
      },
      "cell_type": "code",
      "source": [
        "#@title Make the clock\n",
        "time_step = datetime.timedelta(minutes=20)\n",
        "SETUP_TIME = datetime.datetime(hour=20, year=2024, month=10, day=1)\n",
        "\n",
        "START_TIME = datetime.datetime(hour=18, year=2024, month=10, day=2)\n",
        "clock = game_clock.MultiIntervalClock(\n",
        "    start=SETUP_TIME,\n",
        "    step_sizes=[time_step, datetime.timedelta(seconds=10)])\n"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "h4_gUs6wrjPM"
      },
      "cell_type": "code",
      "source": [
        "#@title Importance models\n",
        "importance_model = importance_function.AgentImportanceModel(model)\n",
        "importance_model_gm = importance_function.ConstantImportanceModel()\n"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "b8vWoQ6by51N"
      },
      "cell_type": "code",
      "source": [
        "# @title Generic memories are memories that all players and GM share.\n",
        "\n",
        "shared_memories = [\n",
        "    'There is a pub called The Sundrop Saloon.',\n",
        "    \"Alice stole Bob's car and crashed it.\",\n",
        "    ('Alice, Bob, Charlie and Dorothy always spend their evenings at the ' +\n",
        "     'Sundrop Saloon.')\n",
        "]\n",
        "\n",
        "# The generic context will be used for the NPC context. It reflects general\n",
        "# knowledge and is possessed by all characters.\n",
        "shared_context = model.sample_text(\n",
        "    'Summarize the following passage in a concise and insightful fashion:\\n'\n",
        "    + '\\n'.join(shared_memories)\n",
        "    + '\\n'\n",
        "    + 'Summary:'\n",
        ")\n",
        "print(shared_context)\n"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "qt8CK2mMbD7q"
      },
      "cell_type": "markdown",
      "source": [
        "## Configure and build the players\n",
        "\n",
        "---\n",
        "\n"
      ]
    },
    {
      "metadata": {
        "id": "CrmDfTNHCVXC"
      },
      "cell_type": "code",
      "source": [
        "blank_memory_factory = blank_memories.MemoryFactory(\n",
        "    model=model,\n",
        "    embedder=embedder,\n",
        "    importance=importance_model.importance,\n",
        "    clock_now=clock.now,\n",
        ")\n",
        "\n",
        "formative_memory_factory = formative_memories.FormativeMemoryFactory(\n",
        "    model=model,\n",
        "    shared_memories=shared_memories,\n",
        "    blank_memory_factory_call=blank_memory_factory.make_blank_memory,\n",
        ")"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "AXnq6aOZ3ukY"
      },
      "cell_type": "code",
      "source": [
        "#@title Creating character backgrounds, goals and traits. Modify to explore how it influences the outcomes\n",
        "NUM_PLAYERS = 4\n",
        "\n",
        "scenario_premise = [\n",
        "    (\n",
        "        'Alice, Bob, Charlie and Dorothy are at the Sundrop Saloon. There '\n",
        "        + 'is a snow storm and they have to wait it out inside.'\n",
        "    ),\n",
        "]\n",
        "player_configs = [\n",
        "    formative_memories.AgentConfig(\n",
        "        name='Alice',\n",
        "        gender='female',\n",
        "        goal='Alice wants Bob to accept his car is trashed and back off.',\n",
        "        context=shared_context,\n",
        "        traits='responsibility: low; aggression: high',\n",
        "    ),\n",
        "    formative_memories.AgentConfig(\n",
        "        name='Bob',\n",
        "        gender='male',\n",
        "        goal='Bob wants Alice to pay for his car.',\n",
        "        context=shared_context,\n",
        "        traits='responsibility: high; aggression: low',\n",
        "    ),\n",
        "    formative_memories.AgentConfig(\n",
        "        name='Charlie',\n",
        "        gender='male',\n",
        "        goal='Charlie wants Alice to apologise.',\n",
        "        context=shared_context,\n",
        "        traits='responsibility: low; aggression: high',\n",
        "    ),\n",
        "    formative_memories.AgentConfig(\n",
        "        name='Dorothy',\n",
        "        gender='female',\n",
        "        goal=(\n",
        "            'Dorothy wants to create a conflict between Bob and Alice, because'\n",
        "            ' it is funny.'\n",
        "        ),\n",
        "        context=shared_context,\n",
        "        traits='responsibility: medium; aggression: high',\n",
        "    ),\n",
        "]"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "4aS2sY22B1JQ"
      },
      "cell_type": "code",
      "source": [
        "def build_agent(agent_config,\n",
        "                player_names: list[str],\n",
        "                measurements: measurements_lib.Measurements | None = None):\n",
        "\n",
        "  mem = formative_memory_factory.make_memories(agent_config)\n",
        "\n",
        "  agent_name = agent_config.name\n",
        "  instructions = generic_components.constant.ConstantComponent(\n",
        "      state=(\n",
        "          f'The instructions for how to play the role of {agent_name} are as '\n",
        "          'follows. This is a social science experiment studying how well you '\n",
        "          f'play the role of a character named {agent_name}. The experiment '\n",
        "          'is structured as a tabletop roleplaying game (like dungeons and '\n",
        "          'dragons). However, in this case it is a serious social science '\n",
        "          'experiment and simulation. The goal is to be realistic. It is '\n",
        "          f'important to play the role of a person like {agent_name} as '\n",
        "          f'accurately as possible, i.e., by responding in ways that you think '\n",
        "          f'it is likely a person like {agent_name} would respond, and taking '\n",
        "          f'into account all information about {agent_name} that you have. '\n",
        "          'Always use third-person limited perspective.'\n",
        "      ),\n",
        "      name='role playing instructions\\n')\n",
        "\n",
        "  time = generic_components.report_function.ReportFunction(\n",
        "    name='Current time',\n",
        "    function=clock.current_time_interval_str,\n",
        "  )\n",
        "\n",
        "  current_obs = components.observation.Observation(\n",
        "            agent_name=agent_config.name,\n",
        "      clock_now=clock.now,\n",
        "      memory=mem,\n",
        "      timeframe=clock.get_step_size(),\n",
        "      component_name='current observations',\n",
        "  )\n",
        "  summary_obs = components.observation.ObservationSummary(\n",
        "      agent_name=agent_config.name,\n",
        "      model=model,\n",
        "      clock_now=clock.now,\n",
        "      memory=mem,\n",
        "      components=[current_obs],\n",
        "      timeframe_delta_from=datetime.timedelta(hours=4),\n",
        "      timeframe_delta_until=datetime.timedelta(hours=1),\n",
        "      component_name='summary of observations',\n",
        "  )\n",
        "\n",
        "  self_perception = components.self_perception.SelfPerception(\n",
        "      name=f'answer to what kind of person is {agent_config.name}',\n",
        "      model=model,\n",
        "      memory=mem,\n",
        "      agent_name=agent_config.name,\n",
        "      clock_now=clock.now,\n",
        "  )\n",
        "  situation_perception = components.situation_perception.SituationPerception(\n",
        "      name=(f'answer to what kind of situation is {agent_config.name} in ' +\n",
        "            'right now'),\n",
        "      model=model,\n",
        "      memory=mem,\n",
        "      agent_name=agent_config.name,\n",
        "      components=[current_obs, summary_obs],\n",
        "      clock_now=clock.now,\n",
        "  )\n",
        "  person_by_situation = components.person_by_situation.PersonBySituation(\n",
        "      name=(f'answer to what would a person like {agent_config.name} do in a ' +\n",
        "            'situation like this'),\n",
        "      model=model,\n",
        "      memory=mem,\n",
        "      agent_name=agent_config.name,\n",
        "      clock_now=clock.now,\n",
        "      components=[self_perception, situation_perception],\n",
        "      verbose=True,\n",
        "  )\n",
        "\n",
        "  initial_goal_component = generic_components.constant.ConstantComponent(\n",
        "      state=agent_config.goal)\n",
        "\n",
        "  persona = generic_components.sequential.Sequential(\n",
        "      name='persona',\n",
        "      components=[\n",
        "          self_perception,\n",
        "          situation_perception,\n",
        "          person_by_situation,\n",
        "      ]\n",
        "  )\n",
        "\n",
        "  goal_metric = goal_achievement.GoalAchievementMetric(\n",
        "      model=model,\n",
        "      player_name=agent_config.name,\n",
        "      player_goal=agent_config.goal,\n",
        "      clock=clock,\n",
        "      name='Goal Achievement',\n",
        "      measurements=measurements,\n",
        "      channel='goal_achievement',\n",
        "      verbose=False,\n",
        "  )\n",
        "  morality_metric = common_sense_morality.CommonSenseMoralityMetric(\n",
        "      model=model,\n",
        "      player_name=agent_config.name,\n",
        "      clock=clock,\n",
        "      name='Morality',\n",
        "      verbose=False,\n",
        "      measurements=measurements,\n",
        "      channel='common_sense_morality',\n",
        "  )\n",
        "  agent = basic_agent.BasicAgent(\n",
        "      model,\n",
        "      agent_name=agent_config.name,\n",
        "      clock=clock,\n",
        "      verbose=False,\n",
        "      components=[instructions,\n",
        "                  persona,\n",
        "                  time,\n",
        "                  current_obs,\n",
        "                  goal_metric,\n",
        "                  morality_metric],\n",
        "      update_interval = time_step\n",
        "  )\n",
        "  reputation_metric = opinion_of_others.OpinionOfOthersMetric(\n",
        "      model=model,\n",
        "      player_name=agent_config.name,\n",
        "      player_names=player_names,\n",
        "      context_fn=agent.state,\n",
        "      clock=clock,\n",
        "      name='Opinion',\n",
        "      verbose=False,\n",
        "      measurements=measurements,\n",
        "      channel='opinion_of_others',\n",
        "      question='What is {opining_player}\\'s opinion of {of_player}?',\n",
        "  )\n",
        "  agent.add_component(reputation_metric)\n",
        "  return agent, mem\n"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "5RU3ZV4oIknW"
      },
      "cell_type": "code",
      "source": [
        "player_configs = player_configs[:NUM_PLAYERS]\n",
        "player_names = [player.name for player in player_configs][:NUM_PLAYERS]\n",
        "measurements = measurements_lib.Measurements()\n",
        "\n",
        "players = []\n",
        "memories = {}\n",
        "\n",
        "with concurrent.futures.ThreadPoolExecutor(max_workers=NUM_PLAYERS) as pool:\n",
        "  for agent, mem in pool.map(build_agent,\n",
        "                             player_configs[:NUM_PLAYERS],\n",
        "                             # All players get the same `player_names`.\n",
        "                             [player_names] * NUM_PLAYERS,\n",
        "                             # All players get the same `measurements` object.\n",
        "                             [measurements] * NUM_PLAYERS):\n",
        "    players.append(agent)\n",
        "    memories[agent.name] = mem\n"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "2vt8ggYUrW8M"
      },
      "cell_type": "markdown",
      "source": [
        "## Build GM"
      ]
    },
    {
      "metadata": {
        "id": "3W65kHOKQwrv"
      },
      "cell_type": "code",
      "source": [
        "game_master_memory = associative_memory.AssociativeMemory(\n",
        "   sentence_embedder=embedder,\n",
        "   importance=importance_model_gm.importance,\n",
        "   clock=clock.now)"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "-cxivChc633z"
      },
      "cell_type": "code",
      "source": [
        "# @title Create components of the Game Master\n",
        "player_names = [player.name for player in players]\n",
        "\n",
        "snowed_in_construct = generic_components.constant.ConstantComponent(\n",
        "    state=(\n",
        "        'It is impossible to leave the Sundrop Saloon, since it is snowed in.'),\n",
        "    name='Fact')\n",
        "scenario_knowledge = generic_components.constant.ConstantComponent(\n",
        "    state=' '.join(shared_memories),\n",
        "    name='Background')\n",
        "\n",
        "player_status = gm_components.player_status.PlayerStatus(\n",
        "    clock_now=clock.now,\n",
        "    model=model,\n",
        "    memory=game_master_memory,\n",
        "    player_names=player_names)\n",
        "\n",
        "\n",
        "convo_externality = gm_components.conversation.Conversation(\n",
        "    players=players,\n",
        "    model=model,\n",
        "    memory=game_master_memory,\n",
        "    clock=clock,\n",
        "    burner_memory_factory=blank_memory_factory,\n",
        "    components=[player_status, snowed_in_construct],\n",
        "    cap_nonplayer_characters=3,\n",
        "    shared_context=shared_context,\n",
        "    verbose=False,\n",
        ")\n",
        "\n",
        "direct_effect_externality = gm_components.direct_effect.DirectEffect(\n",
        "    players=players,\n",
        "    model=model,\n",
        "    memory=game_master_memory,\n",
        "    clock_now=clock.now,\n",
        "    verbose=False,\n",
        "    components=[player_status]\n",
        ")\n",
        "\n",
        "relevant_events = gm_components.relevant_events.RelevantEvents(\n",
        "    clock.now, model, game_master_memory)\n",
        "time_display = gm_components.time_display.TimeDisplay(clock)\n"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "d_R2BVNOsAwa"
      },
      "cell_type": "code",
      "source": [
        "# @title Create the game master object\n",
        "env = game_master.GameMaster(\n",
        "    model=model,\n",
        "    memory=game_master_memory,\n",
        "    clock=clock,\n",
        "    players=players,\n",
        "    components=[\n",
        "        snowed_in_construct,\n",
        "        scenario_knowledge,\n",
        "        player_status,\n",
        "        convo_externality,\n",
        "        direct_effect_externality,\n",
        "        relevant_events,\n",
        "        time_display,\n",
        "    ],\n",
        "    randomise_initiative=True,\n",
        "    player_observes_event=False,\n",
        "    verbose=True,\n",
        ")"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "LXykV_TdwfKq"
      },
      "cell_type": "code",
      "source": [],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "d2u0bQ1MSCGd"
      },
      "cell_type": "markdown",
      "source": [
        "## The RUN"
      ]
    },
    {
      "metadata": {
        "id": "hdTRDaxEZZnN"
      },
      "cell_type": "code",
      "source": [
        "clock.set(START_TIME)"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "9IggLF1aH_hF"
      },
      "cell_type": "code",
      "source": [
        "for premise in scenario_premise:\n",
        "  game_master_memory.add(premise)\n",
        "  for player in players:\n",
        "    player.observe(premise)\n"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "2Bt87stq76gF"
      },
      "cell_type": "code",
      "source": [
        "# @title Expect about 2-3 minutes per step.\n",
        "episode_length = 4  # @param {type: 'integer'}\n",
        "for _ in range(episode_length):\n",
        "  env.step()\n"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "DnwvpvQ4bnFs"
      },
      "cell_type": "markdown",
      "source": [
        "## Summary and analysis of the episode"
      ]
    },
    {
      "metadata": {
        "id": "5U5FDXvs4HSr"
      },
      "cell_type": "code",
      "source": [
        "# @title Metrics plotting\n",
        "\n",
        "group_by = collections.defaultdict(lambda: 'player')\n",
        "group_by['opinion_of_others'] = 'of_player'\n",
        "\n",
        "available_channels = list(measurements.available_channels())\n",
        "\n",
        "fig, ax = plt.subplots(1, len(available_channels), figsize=(6, 2))\n",
        "tb = [channel for channel in available_channels]\n",
        "for idx, channel in enumerate(available_channels):\n",
        "  plotting.plot_line_measurement_channel(measurements, channel,\n",
        "                                         group_by=group_by[channel],\n",
        "                                         xaxis='time_str',\n",
        "                                         ax=ax[idx])\n",
        "  ax[idx].set_title(channel)\n",
        "\n",
        "fig.set_constrained_layout(constrained=True)"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "cHJ7MdyE4oS5"
      },
      "cell_type": "markdown",
      "source": [
        "#Build and display HTML log of the experiment"
      ]
    },
    {
      "metadata": {
        "id": "j71OiuPot5UV"
      },
      "cell_type": "markdown",
      "source": [
        "## Prepare to visualize text results with HTML"
      ]
    },
    {
      "metadata": {
        "id": "O4jp0xGXvOAJ"
      },
      "cell_type": "code",
      "source": [
        "# @title Summarize the entire story.\n",
        "all_gm_memories = env._memory.retrieve_recent(k=10000, add_time=True)\n",
        "\n",
        "detailed_story = '\\n'.join(all_gm_memories)\n",
        "print('len(detailed_story): ', len(detailed_story))\n",
        "# print(detailed_story)\n",
        "\n",
        "episode_summary = model.sample_text(\n",
        "    f'Sequence of events:\\n{detailed_story}'+\n",
        "    '\\nNarratively summarize the above temporally ordered ' +\n",
        "    'sequence of events. Write it as a news report. Summary:\\n',\n",
        "     max_tokens=3500, terminators=())\n",
        "print(episode_summary)"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "ALG987t-6j-V"
      },
      "cell_type": "code",
      "source": [
        "# @title Summarise the perspective of each player\n",
        "player_logs = []\n",
        "player_log_names = []\n",
        "for player in players:\n",
        "  name = player.name\n",
        "  detailed_story = '\\n'.join(memories[player.name].retrieve_recent(\n",
        "      k=1000, add_time=True))\n",
        "  summary = ''\n",
        "  summary = model.sample_text(\n",
        "      f'Sequence of events that happened to {name}:\\n{detailed_story}'\n",
        "      '\\nWrite a short story that summarises these events.\\n'\n",
        "      ,\n",
        "       max_tokens=3500, terminators=())\n",
        "\n",
        "  all_player_mem = memories[player.name].retrieve_recent(k=1000, add_time=True)\n",
        "  all_player_mem = ['Summary:', summary, 'Memories:'] + all_player_mem\n",
        "  player_html = html_lib.PythonObjectToHTMLConverter(all_player_mem).convert()\n",
        "  player_logs.append(player_html)\n",
        "  player_log_names.append(f'{name}')\n"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "JyEoGgI05xI0"
      },
      "cell_type": "code",
      "source": [
        "history_sources = [env, direct_effect_externality, convo_externality]\n",
        "histories_html = [\n",
        "    html_lib.PythonObjectToHTMLConverter(history.get_history()).convert()\n",
        "    for history in history_sources]\n",
        "histories_names = [history.name for history in history_sources]"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "XNJuo4Dwt5Ui"
      },
      "cell_type": "code",
      "source": [
        "gm_mem_html = html_lib.PythonObjectToHTMLConverter(all_gm_memories).convert()\n",
        "\n",
        "tabbed_html = html_lib.combine_html_pages(\n",
        "    histories_html + [gm_mem_html] + player_logs,\n",
        "    histories_names + ['GM'] + player_log_names,\n",
        "    summary=episode_summary,\n",
        "    title='Friends in a pub experiment',\n",
        ")\n",
        "\n",
        "tabbed_html = html_lib.finalise_html(tabbed_html)"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "pumxvmrzANOq"
      },
      "cell_type": "code",
      "source": [
        "display.HTML(tabbed_html)"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "HX-M9Im_dneG"
      },
      "cell_type": "markdown",
      "source": [
        "#Interact with a specific player"
      ]
    },
    {
      "metadata": {
        "id": "ESJ1l7_Kt5Uj"
      },
      "cell_type": "code",
      "source": [
        "sim_to_interact = 'Alice'  # @param ['Alice', 'Bob','Charlie', 'Dorothy', 'Ellen'] {type:\"string\"}\n",
        "user_identity = 'a close friend'  # @param {type:\"string\"}\n",
        "interaction_premise = f'{sim_to_interact} is talking to {user_identity}\\n'  # @param {type:\"string\"}\n",
        "\n",
        "player_names = [player.name for player in players]\n",
        "player_by_name = {player.name: player for player in players}\n",
        "selected_player = player_by_name[sim_to_interact]\n",
        "interrogation = interaction_premise"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "5Q1cYflLt5Uj"
      },
      "cell_type": "code",
      "source": [
        "utterence_from_user = 'Did Bob accept your apology?'  # @param {type:\"string\"}\n",
        "\n",
        "interrogation += f'{user_identity}: {utterence_from_user}'\n",
        "player_says = selected_player.say(interrogation)\n",
        "interrogation += f'\\n{sim_to_interact}: {player_says}\\n'\n",
        "print(interrogation)"
      ],
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {
        "id": "M6Q2VIy839ES"
      },
      "cell_type": "markdown",
      "source": [
        "```\n",
        "Copyright 2023 DeepMind Technologies Limited.\n",
        "\n",
        "Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "you may not use this file except in compliance with the License.\n",
        "You may obtain a copy of the License at\n",
        "\n",
        "    https://www.apache.org/licenses/LICENSE-2.0\n",
        "\n",
        "Unless required by applicable law or agreed to in writing, software\n",
        "distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "See the License for the specific language governing permissions and\n",
        "limitations under the License.\n",
        "```"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "last_runtime": {
        "build_target": "",
        "kind": "private"
      },
      "private_outputs": true,
      "provenance": [],
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
